﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine.SceneManagement;

namespace AssetLoad
{
    public class AssetBundleManager : MonoBehaviour
    {

        /// <summary>
        /// 是否正在加载
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return loadingAsset.Count + waitingTask.Count > 0;
            }
        }
        /// <summary>
        /// assetBundle集合
        /// </summary>
        private Dictionary<string, BundleCounter> bundleContainer = new Dictionary<string, BundleCounter>();
        /// <summary>
        /// inst集合
        /// </summary>
        private Dictionary<string, InstCounter> instContainer = new Dictionary<string, InstCounter>();
        /// <summary>
        /// 正在下载的资源
        /// </summary>
        private Dictionary<string, int> loadingAsset = new Dictionary<string, int>();
        /// <summary>
        /// 处于等待中的任务
        /// </summary>
        private Dictionary<string, int> waitingTask = new Dictionary<string, int>();
        /// <summary>
        /// manifest信息
        /// </summary>
        private AssetBundleManifest bundleManifest;

        public int MAX_WWW_COUNT = 4;

        //public long maxLoadingSize = 10 * 1 << 20;
        //public long loadingSize = 0;

        private AssetFileTool assetFileTool = null;
        private AssetFileTool smallAssetFileTool = null;
        private HashSet<string> errorSet = new HashSet<string>();

        private GameObject replaceObj;
#if !UNITY_EDITOR || TESTASSET
        private int LITTLE_SIZE_THRESHOLD = 10 * 1024;
#endif
        private bool isLoadingScene = false;

        public bool IsLoadingScene
        {
            get
            {
                return isLoadingScene;
            }
        }

        //public void OnGUI()
        //{
        //    if(GUI.Button(new Rect(0,0,100,50),"clear"))
        //    {
        //        Clear();
        //    }
        //}
        /// <summary>
        /// 是否完成初始化
        /// </summary>
        public bool IsInitialized
        {
            get
            {
#if UNITY_EDITOR && !TESTASSET
                return true;
#else
                return bundleManifest != null && assetFileTool != null && smallAssetFileTool != null;
#endif
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void Initialize()
        {
            Clear();

            if (RenderManager.Quality == RenderLevel.High)
            {
                MAX_WWW_COUNT = RenderManager.highWWWCount;
            }
            else if (RenderManager.Quality == RenderLevel.Middle)
            {
                MAX_WWW_COUNT = RenderManager.middleWWWCount;
            }
            else
            {
                MAX_WWW_COUNT = RenderManager.lowWWWCount;
            }
#if UNITY_EDITOR  && !TESTASSET
            return;
#elif UNITY_ANDROID
            StartCoroutine(LoadAndroidManifest("android"));
            //LoadAssetBundleManifest("android");
#elif UNITY_IPHONE
            LoadAssetBundleManifest("ios");
#else
            LoadAssetBundleManifest("pc");
#endif
        }

        public void Clear()
        {
            StopAllCoroutines();
            loadingAsset.Clear();
            waitingTask.Clear();
            errorSet.Clear();
            if (bundleManifest != null)
            {
                bundleManifest = null;
            }
            if (assetFileTool != null)
            {
                assetFileTool.assetCells.Clear();
                assetFileTool = null;
            }
            if (smallAssetFileTool != null)
            {
                smallAssetFileTool.assetCells.Clear();
                smallAssetFileTool = null;
            }
            foreach (var kvp in bundleContainer)
            {
                if (kvp.Value.asset != null)
                {
                    kvp.Value.asset.Unload(false);
                }
            }
            foreach (var ic in instContainer)
            {
                ic.Value.inst = null;
            }
            instContainer.Clear();
            bundleContainer.Clear();
        }

        /// <summary>
        /// 加载assetBundle，同时将依赖的assetBundle也加载进来
        /// </summary>
        /// <param name="bundleName">资源名称</param>
        public void LoadAssetBundle(string bundleName, bool onlyBundle = false)
        {
            bundleName = bundleName.ToLower();
            if (!IsAssetExist(bundleName))
            {
                Debug.LogError("asset not exist " + bundleName);
                string asset = null;
                string preBn = bundleName;
                if (!GetReplaceString(ref bundleName, ref asset))
                {
                    return;
                }
                Debug.LogError("replace " + preBn + " to " + bundleName);
            }
#if UNITY_EDITOR  && !TESTASSET
            LoadAssetBundleSingle(bundleName);
#else
            if (!IsInitialized)
            {
                throw new System.Exception("AssetBundleManager has not initialized");
            }
            if (onlyBundle || LoadInst(bundleName))
            {
                string[] dependencies = bundleManifest.GetAllDependencies(bundleName);
                if (dependencies == null)
                {
                    return;
                }
                for (int i = 0; i < dependencies.Length; ++i)
                {
                    LoadAssetBundleSingle(dependencies[i]);
                }
                LoadAssetBundleSingle(bundleName);
                if(onlyBundle)
                {
                    Debug.Log("asset "+ bundleName +" dependent count: " + dependencies.Length);
                }
            }
            //Debug.Log(bundleContainer.Count);
#endif

        }
        public readonly string commonScene = "map_forest_002";//"map_forest_002";
        public readonly string commonScenePath = "map/map_forest_002";//"map/map_forest_002";
        public readonly string navScene = "nav";

        public IEnumerator LoadSceneAsync(string bundleName, string sceneName, bool isAdd = false)
        {
            Debug.Log("<color=yellow>bundleCount " + bundleContainer.Count + "</color>");
            Debug.Log("<color=yellow>instCount " + instContainer.Count + "</color>");
            //FileLog.Log("##################bundleCount " + bundleContainer.Count + "instCount " + instContainer.Count + "##################");
            //FileLog.Log("###########         bundle       ######");
            //foreach(var bc in bundleContainer)
            //{
            //    FileLog.Log(bc.Key + ":   "+bc.Value.count);
            //}
            //FileLog.Log("###########         inst       ######");
            //foreach (var ic in instContainer)
            //{
            //    FileLog.Log(ic.Key + ":   " + ic.Value.count);
            //}
            System.DateTime dt = System.DateTime.Now;
            bundleName = bundleName.ToLower();
            //int maxCount = MAX_WWW_COUNT;
            //MAX_WWW_COUNT = 20;
            if (!IsAssetExist(bundleName))
            {
                Debug.LogError("scene " + sceneName + " not exist!");
                if (bundleName.IndexOf("run") != -1 || bundleName.IndexOf("field") != -1 || bundleName.IndexOf(navScene) != -1)
                {
                    bundleName = navScene;
                    sceneName = navScene;
                }
                else
                {
                    bundleName = commonScenePath;
                    sceneName = commonScene;
                }
            }
            if (!isAdd)
            {
                if (sceneName == SceneManager.GetActiveScene().name)
                {
                    foreach (var gobj in SceneManager.GetActiveScene().GetRootGameObjects())
                    {
                        gobj.SetActive(true);
                    }
#if UNITY_EDITOR
                    Debug.Log("load the same scene " + bundleName);
#endif
                    //MAX_WWW_COUNT = maxCount;
                    yield break;
                }
                SceneManager.LoadScene("empty");
                yield return 1;
                Debug.Log("switch to empty cost time " + (System.DateTime.Now - dt).TotalMilliseconds + "ms");
            }
#if UNITY_EDITOR  && !TESTASSET
            string[] levelPaths = UnityEditor.AssetDatabase.GetAssetPathsFromAssetBundleAndAssetName(bundleName, sceneName);
            if (levelPaths.Length == 0)
            {
                ///@TODO: The error needs to differentiate that an asset bundle name doesn't exist
                //        from that there right scene does not exist in the asset bundle...

                Debug.LogError("There is no scene with name \"" + bundleName + "\" in " + sceneName);
                yield break;
            }
            if (!isAdd)
            {
                yield return UnityEditor.EditorApplication.LoadLevelAsyncInPlayMode(levelPaths[0]);
            }
            else
            {
                yield return UnityEditor.EditorApplication.LoadLevelAdditiveAsyncInPlayMode(levelPaths[0]);
            }
#else
            isLoadingScene = true;
            if (bundleName != navScene)
            {
                LoadAssetBundle(bundleName, true);
                while (!IsLoadedAssetBundle(bundleName))
                {
                    yield return null;
                }
                Debug.Log(sceneName + " loading bundles cost time " + (System.DateTime.Now - dt).TotalMilliseconds + "ms");
            }
            if (!isAdd)
            {
                if (SceneManager.GetSceneByName(sceneName).isLoaded)
                {
                    yield break;
                }
                SceneManager.LoadScene(sceneName);
                yield return 1;
                //yield return SceneManager.LoadSceneAsync(sceneName);
            }
            else
            {
                SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);
                yield return 1;
                //yield return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
            }
            Debug.Log(sceneName + " loading cost time " + (System.DateTime.Now - dt).TotalMilliseconds + "m");
            if (bundleName != navScene)
            {
                UnloadAssetBundle(bundleName);
            }
            //MAX_WWW_COUNT = maxCount;
            //Debug.Log("<color=yellow>loading size " + loadingSize + "</color>");
#endif
            isLoadingScene = false;
            Debug.Log(sceneName + " unload bundle cost time " + (System.DateTime.Now - dt).TotalMilliseconds + "ms");
        }

        /// <summary>
        /// 协程方式加载资源
        /// </summary>
        /// <param name="bundleName"></param>
        /// <returns></returns>
        public IEnumerator LoadAssetBundleCoroutine(string bundleName)
        {
            bundleName = bundleName.ToLower();
            LoadAssetBundle(bundleName);
            while (!IsLoadedAssetBundle(bundleName))
            {
                yield return null;
            }
        }

        public IEnumerator LoadAndInstAssetCoroutine(string assetBundleName, string assetName,System.Action<bool> loadCallback)
        {
            assetBundleName = assetBundleName.ToLower();
            if (!IsAssetExist(assetBundleName))
            {
                Debug.LogError("asset not exist " + assetBundleName);
                string asset = null;
                string preBn = assetBundleName;
                if (!GetReplaceString(ref assetBundleName, ref asset))
                {
                    loadCallback(false);
                    yield break;
                }
                Debug.LogError("replace " + preBn + " to " + assetBundleName);
            }
            LoadAssetBundle(assetBundleName);
#if UNITY_EDITOR && !TESTASSET
            loadCallback(true);
            yield break;
#else
            while (!IsLoadedAssetBundle(assetBundleName))
            {
                if((!bundleContainer.ContainsKey(assetBundleName) || bundleContainer[assetBundleName].count <= 0) && (instContainer.ContainsKey(assetBundleName) || instContainer[assetBundleName].count <= 0)
                    && !loadingAsset.ContainsKey(assetBundleName) && !waitingTask.ContainsKey(assetBundleName))
                {
                    if(loadCallback != null)
                    {
                        loadCallback(false);
                    }
                    yield break;
                }
                yield return null;
            }

            if (instContainer.ContainsKey(assetBundleName) && instContainer[assetBundleName].inst != null)
            {
                if(loadCallback != null)
                {
                    loadCallback(true);
                }
                yield break;
            }
            else
            {
                if (bundleContainer.ContainsKey(assetBundleName) && bundleContainer[assetBundleName].asset != null)
                {
                    AssetBundle ab = bundleContainer[assetBundleName].asset;//.LoadAsset(assetName);
                    bundleContainer[assetBundleName].busyNumber++;
                    string[] dependencies = bundleManifest.GetAllDependencies(assetBundleName);
                    if (dependencies != null)
                    {
                        for (int i = 0; i < dependencies.Length; ++i)
                        {
                            bundleContainer[dependencies[i]].busyNumber++;
                        }
                    }
                    
                    var asyn = ab.LoadAssetAsync(assetName);
                    while(true)
                    {
                        if(asyn.isDone)
                        {
                            bundleContainer[assetBundleName].busyNumber--;
                            if (dependencies != null)
                            {
                                for (int i = 0; i < dependencies.Length; ++i)
                                {
                                    bundleContainer[dependencies[i]].busyNumber--;
                                }
                            }
                            //if()
                            //instContainer[assetBundleName].inst = asyn.asset;
                            UnloadBundleOnly(assetBundleName, 0);
                            if (loadCallback != null)
                            {
                                loadCallback(true);
                            }
                            yield break;
                        }
                        else
                        {
                            yield return 1;
                        }
                    }
                    
                }
                else
                {
                    if (loadCallback != null)
                    {
                        loadCallback(false);
                    }
                    yield break;
                }
            }
#endif
        }
        /// <summary>
        /// 卸载assetBundle，同时将依赖的assetBundle也卸载出去
        /// </summary>
        /// <param name="bundleName">资源名称</param>
        public void UnloadAssetBundle(string bundleName, int number = 1)
        {
            bundleName = bundleName.ToLower();
            if (!IsAssetExist(bundleName))
            {
                Debug.LogError("unload asset " + bundleName + " not exist");
                string asset = null;
                if (!GetReplaceString(ref bundleName, ref asset))
                {
                    return;
                }
            }
#if UNITY_EDITOR && !TESTASSET
            UnloadAssetBundleSingle(bundleName,number);
#else
            if (!IsInitialized)
            {
                Debug.LogError("AssetBundleManager has not initialized");
                return;
            }
            if (instContainer.ContainsKey(bundleName) && instContainer[bundleName].inst != null)
            {
                instContainer[bundleName].count -= number;
                if (instContainer[bundleName].count <= 0)
                {
                    instContainer[bundleName].inst = null;
                    instContainer.Remove(bundleName);
                    return;
                }
            }
            else
            {
                if (instContainer.ContainsKey(bundleName) && instContainer[bundleName].inst == null)
                {
                    instContainer[bundleName].count -= number;
                    if (instContainer[bundleName].count <= 0)
                    {
                        instContainer.Remove(bundleName);
                    }
                }
                //if(bundleContainer.ContainsKey())
                UnloadAssetBundleSingle(bundleName, number);
                string[] dependencies = bundleManifest.GetAllDependencies(bundleName);
                if (dependencies == null)
                {
                    return;
                }
                for (int i = 0; i < dependencies.Length; ++i)
                {
                    UnloadAssetBundleSingle(dependencies[i], number);
                }
            }

#endif
        }

        private void UnloadBundleOnly(string bundleName, int number)
        {
            bundleName = bundleName.ToLower();
            if (!IsAssetExist(bundleName))
            {
                Debug.LogError("unload asset " + bundleName + " not exist");
                string asset = null;
                if (!GetReplaceString(ref bundleName, ref asset))
                {
                    return;
                }
            }
#if UNITY_EDITOR && !TESTASSET
            UnloadAssetBundleSingle(bundleName,number);
#else
            if (!IsInitialized)
            {
                throw new System.Exception("AssetBundleManager has not initialized");
            }
            UnloadAssetBundleSingle(bundleName, number);
            string[] dependencies = bundleManifest.GetAllDependencies(bundleName);
            if (dependencies == null)
            {
                return;
            }
            for (int i = 0; i < dependencies.Length; ++i)
            {
                UnloadAssetBundleSingle(dependencies[i], number);
            }
#endif
        }

        //public void Update()
        //{
        //    if (!IsInitialized)
        //    {
        //        return;
        //    }
        //    else
        //    {
        //        if (loadingAsset.Count >= MAX_WWW_COUNT)
        //        {
        //            return;
        //        }
        //        else if (waitingTask.Count > 0)
        //        {
        //            List<string> itemsToRemove = new List<string>();
        //            foreach (var task in waitingTask)
        //            {
        //                loadingAsset.Add(task.Key, task.Value);
        //                StartCoroutine(LoadAssetBundleSingle0(task.Key));
        //                itemsToRemove.Add(task.Key);
        //                if (loadingAsset.Count >= MAX_WWW_COUNT)
        //                {
        //                    break;
        //                }
        //            }
        //            foreach (var item in itemsToRemove)
        //            {
        //                waitingTask.Remove(item);
        //            }
        //        }
        //    }
        //}

        private void LoadNext()
        {
            if (waitingTask.Count > 0)
            {
                foreach (var task in waitingTask)
                {
                    loadingAsset.Add(task.Key, task.Value);
                    waitingTask.Remove(task.Key);
                    StartCoroutine(LoadAssetBundleSingle0(task.Key));
                    break;
                }
            }
        }

        /// <summary>
        /// 加载assetBundle资源
        /// </summary>
        /// <param name="bundleName"></param>
        private void LoadAssetBundleSingle(string bundleName)
        {
            if (bundleContainer.ContainsKey(bundleName))
            {
                bundleContainer[bundleName].count++;
            }
            else if (loadingAsset.ContainsKey(bundleName))
            {
                loadingAsset[bundleName] = loadingAsset[bundleName] + 1;
            }
            else
            {
                if (waitingTask.ContainsKey(bundleName))
                {
                    waitingTask[bundleName] = waitingTask[bundleName] + 1;
                }
                else
                {
                    waitingTask.Add(bundleName, 1);
                }
            }
            if (IsInitialized && loadingAsset.Count < MAX_WWW_COUNT)
            {
                LoadNext();
            }
        }

        public bool LoadInst(string bundleName)
        {
            if (instContainer.ContainsKey(bundleName))
            {
                ++instContainer[bundleName].count;
                return instContainer[bundleName].inst == null;
            }
            else
            {
                instContainer.Add(bundleName, new InstCounter(null, 1));
                return true;
            }
        }

        public bool IsAssetError(string bundleName)
        {
            return errorSet.Contains(bundleName.ToLower());
        }

        /// <summary>
        /// 资源是否加载
        /// </summary>
        /// <param name="bundleName"></param>
        /// <returns></returns>
        public bool IsLoadedAssetBundle(string bundleName)
        {
            bundleName = bundleName.ToLower();
            string assetName = null;
            if (errorSet.Contains(bundleName))
            {
                return true;
            }
            if (!IsAssetExist(bundleName))
            {
                if (!GetReplaceString(ref bundleName, ref assetName))
                    return true;
            }
#if UNITY_EDITOR && !TESTASSET
            if (!bundleContainer.ContainsKey(bundleName))
            {
                return false;
            }
            return true;
#else
            if (bundleName.StartsWith("audio/")) //特殊处理音效
            {
                return bundleContainer.ContainsKey(bundleName);
            }
            if (instContainer.ContainsKey(bundleName) && instContainer[bundleName].inst != null)
            {
                return true;
            }
            if (!bundleContainer.ContainsKey(bundleName))
            {
                //Debug.Log(bundleName + " not loaded ");
                return false;
            }
            string[] dependencies = bundleManifest.GetAllDependencies(bundleName);
            foreach (string dep in dependencies)
            {
                if (!bundleContainer.ContainsKey(dep) && !errorSet.Contains(dep))
                {
                    //Debug.Log(dep + " not loaded ");
                    return false;
                }
            }
            return true;
#endif
        }


        private void LoadAssetBundleManifest(string bundleName)
        {
            AssetBundle asset = GetBundleSimple(bundleName);
            bundleManifest = asset.LoadAsset("assetbundlemanifest") as AssetBundleManifest;
            asset.Unload(false);
            bool isFile;
            string path = GetFullPath("smallassetmanifest", out isFile, true);
            if (isFile)
            {
                smallAssetFileTool = AssetFileTool.LoadFromFile(path);
            }
            else
            {
                Debug.LogError("small asset manifest file not exist");

                TextAsset ta = Resources.Load<TextAsset>(path);
                smallAssetFileTool = AssetFileTool.LoadFromString(ta.text);
                Resources.UnloadAsset(ta);
            }
#if !UNITY_IPHONE
            path = GetFullPath("assetmanifest", out isFile, true);
#else
			path = Application.temporaryCachePath + "/assetmanifest";
			isFile = File.Exists(path);
#endif
            if (isFile)
            {
                assetFileTool = AssetFileTool.LoadFromFile(path);
            }
            else
            {
                assetFileTool = smallAssetFileTool;
            }
        }

        public IEnumerator LoadAndroidManifest(string bundleName)
        {
            AssetBundle asset = GetBundleSimple(bundleName);
            bundleManifest = asset.LoadAsset("assetbundlemanifest") as AssetBundleManifest;
            asset.Unload(false);
            bool isFile;
            string path = GetFullPath("smallassetmanifest", out isFile, true);
            if (isFile)
            {
                smallAssetFileTool = AssetFileTool.LoadFromFile(path);
            }
            else
            {
                Debug.LogError("small asset manifest file not exist");
                WWW www = new WWW(path);
                yield return www;
                smallAssetFileTool = AssetFileTool.LoadFromString(www.text);
                www.Dispose();
            }
            path = GetFullPath("assetmanifest", out isFile, true);
            if (isFile)
            {
                assetFileTool = AssetFileTool.LoadFromFile(path);
            }
            else
            {
                assetFileTool = smallAssetFileTool;
            }
        }

        //public int frameCount = 0;
        //public void LateUpdate()
        //{
        //    if (frameCount > 0)
        //    {
        //        Debug.Log("frame load time " + frameCount);
        //    }
        //    frameCount = 0;
        //}


        /// <summary>
        /// 加载资源协程方法
        /// </summary>
        /// <param name="bundleName"></param>
        /// <returns></returns>
        private IEnumerator LoadAssetBundleSingle0(string bundleName)
        {
            //++frameCount;
            //Debug.Log("<color=yellow>" + ++number + "</color>");
            //Debug.Log("<color=cyan>" + bundleName + "</color>");
            if (errorSet.Contains(bundleName))
            {
                loadingAsset.Remove(bundleName);
                LoadNext();
                yield break;
            }
#if !UNITY_EDITOR || TESTASSET
            //while(loadingSize > maxLoadingSize)
            //{
            //    yield return 1;
            //}
            long size = GetSize(bundleName);
            //loadingSize += size;

            bool isFile;
            string path = GetFullPath(bundleName, out isFile);

            AssetBundle asset = null;
            if (isLoadingScene && size < LITTLE_SIZE_THRESHOLD)
            {
                asset = AssetBundle.LoadFromFile(path);
            }
            else
            {
                //asset = AssetBundle.LoadFromFile(path);
                //if (isFile)
                //{
                AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(path);
	            if (abcr == null)
	            {
	                Debug.LogError("load " + bundleName + " error ");
	                errorSet.Add(bundleName);
	                loadingAsset.Remove(bundleName);
	                LoadNext();
	                //loadingSize -= size;
	                yield break;
	            }
	            else
	            {
	                while (!abcr.isDone)
	                {
	                    yield return 1;
	                }
	                //abcr.allowSceneActivation = true;
	                asset = abcr.assetBundle;
	                abcr = null;
	            }
			}
				
            //}
            //else
            //{
            //    ResourceRequest rr = Resources.LoadAsync<TextAsset>(path);
            //    if(rr == null)
            //    {
            //        Debug.LogError("load " + bundleName + " error ");
            //        errorSet.Add(bundleName);
            //        loadingAsset.Remove(bundleName);
            //        LoadNext();
            //        yield break;
            //    }
            //    else
            //    {
            //        while (!rr.isDone)
            //        {
            //            yield return 1;
            //        }
            //        asset = AssetBundle.LoadFromMemory(((TextAsset)rr.asset).bytes);
            //        Resources.UnloadAsset(rr.asset);
            //        rr = null;
            //    }
            //}
#else
            AssetBundle asset = null;
            yield return 1;
#endif
            int count = loadingAsset[bundleName];
            if (bundleName.StartsWith("resources/com") || bundleName == "shader")
            {
                ++count;
            }
            BundleCounter bc = new BundleCounter(asset, count, CommonMethod.GetAssetNameFromAssetBundleName(bundleName));
            loadingAsset.Remove(bundleName);
            bundleContainer[bundleName] = bc;
            //loadingSize -= size;
#if !UNITY_EDITOR || TESTASSET
#endif
            LoadNext();
        }

        /// <summary>
        /// 获取assetbuddle全路径
        /// </summary>
        /// <param name="bundleName"></param>
        /// <returns></returns>
        public string GetFullPath(string bundleName, out bool isFile, bool isManifest = false)
        {
            bundleName = bundleName.ToLower();
#if UNITY_ANDROID
            string tempPath = Application.persistentDataPath + "/" + bundleName;
#elif UNITY_IPHONE
            string tempPath = Application.temporaryCachePath + "/" + bundleName;
#else
            string tempPath = Application.persistentDataPath + "/" + bundleName;
#endif
            isFile = File.Exists(tempPath);
            if (isFile)
            {
                return tempPath;
            }
            else
            {
#if UNITY_ANDROID
#if UNITY_EDITOR
                isFile = !isManifest;
                if (isFile)
                {
                    return Application.streamingAssetsPath + "/android/" + bundleName;
                }
                else
                {
                    return "file:///" + Application.streamingAssetsPath + "/android/" + bundleName;
                }
#else
                isFile = !isManifest;
                if (isFile)
                {
                    return Application.dataPath + "!assets/android/" + bundleName;
                }
                else
                {
                    return Application.streamingAssetsPath + "/android/" + bundleName;
                }
#endif

#elif UNITY_IPHONE
				isFile = true;
				return Application.streamingAssetsPath + "/ios/" + bundleName;
#else
                isFile = true;
                path = Application.streamingAssetsPath + "/pc/" + bundleName;
                return path;
#endif
            }
        }


        /// <summary>
        /// 获取资源
        /// </summary>
        /// <param name="bundleName">资源名称</param>
        /// <returns>如果已经下载完成直接返回资源，如果为完成返回null</returns>
        public AssetBundle GetAssetBundle(string bundleName)
        {
            bundleName = bundleName.ToLower();
            if (IsLoadedAssetBundle(bundleName) && bundleContainer.ContainsKey(bundleName))
            {
                return bundleContainer[bundleName].asset;
            }
            else
            {
                return null;
            }
        }
        public Object GetAssetFromBundle(string assetBundleName, string assetName, System.Type type)
        {
            assetBundleName = assetBundleName.ToLower();
            assetName = assetName.ToLower();
            if (!IsAssetExist(assetBundleName))
            {
                if (type == typeof(GameObject))
                {
                    if (!GetReplaceString(ref assetBundleName, ref assetName))
                    {
                        if (replaceObj == null)
                        {
                            replaceObj = new GameObject("replaceObj");
                            DontDestroyOnLoad(replaceObj);
                        }
                        return replaceObj;
                    }
                    else
                    {

                    }
                }
                else
                {
                    return null;
                }
            }
#if UNITY_EDITOR && !TESTASSET
            //if (SimulateAssetBundleInEditor)
            //{
            string[] assetPaths = UnityEditor.AssetDatabase.GetAssetPathsFromAssetBundleAndAssetName(assetBundleName, assetName);
            if (assetPaths.Length == 0)
            {
                Debug.LogError("There is no asset with name \"" + assetName + "\" in " + assetBundleName);
                return null;
            }

            // @TODO: Now we only get the main object from the first asset. Should consider type also.
            return UnityEditor.AssetDatabase.LoadMainAssetAtPath(assetPaths[0]);
            //}
            //else
            //{
            //    AssetBundle ab = GetAssetBundle(assetBundleName);
            //    if (ab == null)
            //    {
            //        return null;
            //    }
            //    else
            //    {
            //        return ab.LoadAsset(assetName, type);
            //    }
            //}
#else

            if (instContainer.ContainsKey(assetBundleName) && instContainer[assetBundleName].inst != null)
            {
                return instContainer[assetBundleName].inst;
            }
            else
            {
                if (bundleContainer.ContainsKey(assetBundleName) && bundleContainer[assetBundleName].asset != null)
                {
                    Object inst = bundleContainer[assetBundleName].asset.LoadAsset(assetName, type);
                    if (assetBundleName.StartsWith("audio/"))
                    {
                        return inst;
                    }
                    UnloadBundleOnly(assetBundleName, instContainer[assetBundleName].count);
                    instContainer[assetBundleName].inst = inst;
                    return inst;
                }
                else
                {
                    return null;
                }
            }
            //AssetBundle ab = GetAssetBundle(assetBundleName);
            //if (ab == null)
            //{
            //    if (type == typeof(GameObject))
            //    {
            //        if (!GetReplaceString(ref assetBundleName, ref assetName))
            //        {
            //            if (replaceObj == null)
            //            {
            //                replaceObj = new GameObject("replaceObj");
            //                DontDestroyOnLoad(replaceObj);
            //            }
            //            return replaceObj;
            //        }
            //        else
            //        {
            //            ab = GetAssetBundle(assetBundleName);
            //            if (ab != null)
            //            {
            //                return ab.LoadAsset(assetName, type);
            //            }
            //        }
            //    }
            //    return null;
            //}
            //else
            //{
            //    return ab.LoadAsset(assetName, type);
            //}
#endif
        }

        private void UnloadAssetBundleSingle(string bundleName, int number)
        {
            if (bundleContainer.ContainsKey(bundleName))
            {
                BundleCounter bc = bundleContainer[bundleName];
                bc.count -= number;
                if (bc.count == 0)
                {
#if !UNITY_EDITOR || TESTASSET
					if(bc.busyNumber <= 0 && bc.asset != null)
                    {
                        bc.asset.Unload(false);
                    }
#endif
                    bundleContainer.Remove(bundleName);
                }
            }
            else if (waitingTask.ContainsKey(bundleName))
            {
                if (waitingTask[bundleName] == number)
                {
                    waitingTask.Remove(bundleName);
                }
                else
                {
                    waitingTask[bundleName] = waitingTask[bundleName] - number;
                }
            }
            else if (loadingAsset.ContainsKey(bundleName))
            {
                loadingAsset[bundleName] -= number;
            }
            else
            {
                Debug.LogError("Unload assetbundle error, " + bundleName + " doesn't be loaded!!!");
            }

        }

        public bool IsAssetExist(string asName)
        {
            //if(asName == commonScenePath || asName == "model/"+commonHero || asName == "map/map_city_001")
            //{
            //    return true;
            //}
            //return false;
#if UNITY_EDITOR && !TESTASSET
            return true;
#else
            if (assetFileTool == null || smallAssetFileTool == null)
            {
                return true;
            }
            else
            {
                return assetFileTool.assetCells.ContainsKey(asName) || smallAssetFileTool.assetCells.ContainsKey(asName);
            }
#endif
        }

        public AssetBundle GetBundleSimple(string bundleName)
        {
            bool isFile;
            string path = GetFullPath(bundleName, out isFile);
            return AssetBundle.LoadFromFile(path);
            //if (isFile)
            //{
            //    return AssetBundle.LoadFromFile(path);
            //}
            //else
            //{
            //    var ta = Resources.Load<TextAsset>(path);
            //    if (ta != null)
            //    {
            //        AssetBundle ab = AssetBundle.LoadFromMemory(ta.bytes);
            //        Resources.UnloadAsset(ta);
            //        return ab;
            //    }
            //    else
            //    {
            //        return null;
            //    }
            //}
        }

        public long GetSize(string bundleName)
        {
            if (assetFileTool.assetCells.ContainsKey(bundleName))
            {
                return assetFileTool.assetCells[bundleName].size;
            }
            else if (smallAssetFileTool.assetCells.ContainsKey(bundleName))
            {
                return smallAssetFileTool.assetCells[bundleName].size;
            }
            else
            {
                Debug.Log("error bundle " + bundleName);
                return 0;
            }
        }

#region 代替资源
        private string commonHero = "monster_032";
        public bool GetReplaceString(ref string bundleName, ref string assetName)
        {
            if (bundleName.StartsWith("model/") && !bundleName.EndsWith("_battle"))
            {
                bundleName = "model/" + commonHero;
                if (assetName != null)
                {
                    assetName = commonHero;
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public string GetReplaceSceneName(string sceneName)
        {
            if (IsAssetExist("map/" + sceneName))
            {
                return sceneName;
            }
            else
            {
                if (sceneName.IndexOf("run") != -1 || sceneName.IndexOf("field") != -1)
                {
                    return navScene;
                }
                return commonScene;
            }
        }
#endregion

#region 单例
        private void Awake()
        {
            instance = this;//gameObject.GetComponent<AssetBundleManager>();
            instance.Initialize();
        }

        private static AssetBundleManager instance;
        public static AssetBundleManager Instance
        {
            get
            {
                return instance;
            }
        }
#endregion 单例
    }

}

